package com.kelab.dify.service;

import com.kelab.dify.config.DifyConfig;
import com.kelab.dify.exception.DifyException;
import com.kelab.dify.model.chat.ChatRequest;
import com.kelab.dify.model.chat.ChatResponse;
import com.kelab.dify.service.base.BaseService;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.*;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import okhttp3.sse.EventSources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

/**
 * 聊天服务类
 * 提供Chat Completion API的所有功能
 * 
 * @author kelab
 * @version 1.0
 */
public class ChatService extends BaseService {
    
    private static final Logger logger = LoggerFactory.getLogger(ChatService.class);
    
    private static final String CHAT_MESSAGES_ENDPOINT = "chat-messages";
    private static final String CONVERSATIONS_ENDPOINT = "conversations";
    private static final String MESSAGES_ENDPOINT = "messages";
    private static final String PARAMETERS_ENDPOINT = "parameters";
    
    /**
     * 构造函数
     * 
     * @param httpClient HTTP客户端
     * @param objectMapper JSON映射器
     * @param config 配置信息
     */
    public ChatService(OkHttpClient httpClient, ObjectMapper objectMapper, DifyConfig config) {
        super(httpClient, objectMapper, config);
    }
    
    /**
     * 发送聊天消息（阻塞模式）
     * 
     * @param request 聊天请求
     * @return 聊天响应
     * @throws DifyException 如果请求失败
     */
    public ChatResponse sendMessage(ChatRequest request) throws DifyException {
        request.setResponseMode("blocking");
        
        String json = toJson(request);
        RequestBody body = RequestBody.create(json, JSON_MEDIA_TYPE);
        
        Request httpRequest = new Request.Builder()
                .url(config.getFullUrl(CHAT_MESSAGES_ENDPOINT))
                .post(body)
                .addHeader("Authorization", config.getAuthorizationHeader())
                .addHeader("Content-Type", "application/json")
                .build();
        
        try (Response response = httpClient.newCall(httpRequest).execute()) {
            return handleResponse(response, ChatResponse.class);
        } catch (IOException e) {
            throw new DifyException("Failed to send chat message", e);
        }
    }
    
    /**
     * 发送聊天消息（流式模式）
     * 
     * @param request 聊天请求
     * @param onMessage 消息回调函数
     * @param onError 错误回调函数
     * @return CompletableFuture，可用于等待流式响应完成
     * @throws DifyException 如果请求失败
     */
    public CompletableFuture<Void> sendMessageStream(ChatRequest request, 
                                                    Consumer<ChatResponse> onMessage,
                                                    Consumer<Throwable> onError) throws DifyException {
        request.setResponseMode("streaming");
        
        String json = toJson(request);
        RequestBody body = RequestBody.create(json, JSON_MEDIA_TYPE);
        
        Request httpRequest = new Request.Builder()
                .url(config.getFullUrl(CHAT_MESSAGES_ENDPOINT))
                .post(body)
                .addHeader("Authorization", config.getAuthorizationHeader())
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "text/event-stream")
                .build();
        
        CompletableFuture<Void> future = new CompletableFuture<>();
        
        EventSourceListener listener = new EventSourceListener() {
            @Override
            public void onOpen(EventSource eventSource, Response response) {
                logger.debug("SSE connection opened");
            }
            
            @Override
            public void onEvent(EventSource eventSource, String id, String type, String data) {
                try {
                    if (data != null && !data.trim().isEmpty()) {
                        ChatResponse chatResponse = objectMapper.readValue(data, ChatResponse.class);
                        onMessage.accept(chatResponse);
                        
                        // 检查是否为结束事件
                        if ("message_end".equals(chatResponse.getEvent()) || 
                            "workflow_finished".equals(chatResponse.getEvent())) {
                            future.complete(null);
                        }
                    }
                } catch (Exception e) {
                    logger.error("Error parsing SSE data: {}", data, e);
                    onError.accept(e);
                    future.completeExceptionally(e);
                }
            }
            
            @Override
            public void onClosed(EventSource eventSource) {
                logger.debug("SSE connection closed");
                if (!future.isDone()) {
                    future.complete(null);
                }
            }
            
            @Override
            public void onFailure(EventSource eventSource, Throwable t, Response response) {
                logger.error("SSE connection failed", t);
                onError.accept(t);
                future.completeExceptionally(t);
            }
        };
        
        EventSource eventSource = EventSources.createFactory(httpClient).newEventSource(httpRequest, listener);
        
        // 设置超时处理
        future.whenComplete((result, throwable) -> {
            eventSource.cancel();
        });
        
        return future;
    }
    
    /**
     * 获取对话历史
     * 
     * @param conversationId 对话ID
     * @param user 用户标识
     * @return 对话历史响应
     * @throws DifyException 如果请求失败
     */
    public ConversationResponse getConversation(String conversationId, String user) throws DifyException {
        String url = config.getFullUrl(CONVERSATIONS_ENDPOINT + "/" + conversationId);
        
        Request request = new Request.Builder()
                .url(url + "?user=" + user)
                .get()
                .addHeader("Authorization", config.getAuthorizationHeader())
                .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            return handleResponse(response, ConversationResponse.class);
        } catch (IOException e) {
            throw new DifyException("Failed to get conversation", e);
        }
    }
    
    /**
     * 获取对话消息列表
     * 
     * @param conversationId 对话ID
     * @param user 用户标识
     * @param firstId 第一条消息ID（可选）
     * @param limit 限制数量（可选）
     * @return 消息列表响应
     * @throws DifyException 如果请求失败
     */
    public MessagesResponse getMessages(String conversationId, String user, String firstId, Integer limit) throws DifyException {
        StringBuilder urlBuilder = new StringBuilder(config.getFullUrl(MESSAGES_ENDPOINT));
        urlBuilder.append("?conversation_id=").append(conversationId);
        urlBuilder.append("&user=").append(user);
        
        if (firstId != null && !firstId.isEmpty()) {
            urlBuilder.append("&first_id=").append(firstId);
        }
        if (limit != null && limit > 0) {
            urlBuilder.append("&limit=").append(limit);
        }
        
        Request request = new Request.Builder()
                .url(urlBuilder.toString())
                .get()
                .addHeader("Authorization", config.getAuthorizationHeader())
                .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            return handleResponse(response, MessagesResponse.class);
        } catch (IOException e) {
            throw new DifyException("Failed to get messages", e);
        }
    }
    
    /**
     * 获取对话列表
     * 
     * @param user 用户标识
     * @param lastId 最后一个对话ID（可选）
     * @param limit 限制数量（可选）
     * @param pinned 是否只获取置顶对话（可选）
     * @return 对话列表响应
     * @throws DifyException 如果请求失败
     */
    public ConversationsResponse getConversations(String user, String lastId, Integer limit, Boolean pinned) throws DifyException {
        StringBuilder urlBuilder = new StringBuilder(config.getFullUrl(CONVERSATIONS_ENDPOINT));
        urlBuilder.append("?user=").append(user);
        
        if (lastId != null && !lastId.isEmpty()) {
            urlBuilder.append("&last_id=").append(lastId);
        }
        if (limit != null && limit > 0) {
            urlBuilder.append("&limit=").append(limit);
        }
        if (pinned != null) {
            urlBuilder.append("&pinned=").append(pinned);
        }
        
        Request request = new Request.Builder()
                .url(urlBuilder.toString())
                .get()
                .addHeader("Authorization", config.getAuthorizationHeader())
                .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            return handleResponse(response, ConversationsResponse.class);
        } catch (IOException e) {
            throw new DifyException("Failed to get conversations", e);
        }
    }
    
    /**
     * 删除对话
     * 
     * @param conversationId 对话ID
     * @param user 用户标识
     * @return 删除结果
     * @throws DifyException 如果请求失败
     */
    public DeleteResponse deleteConversation(String conversationId, String user) throws DifyException {
        String url = config.getFullUrl(CONVERSATIONS_ENDPOINT + "/" + conversationId);
        
        RequestBody body = RequestBody.create("{\"user\":\"" + user + "\"}", JSON_MEDIA_TYPE);
        
        Request request = new Request.Builder()
                .url(url)
                .delete(body)
                .addHeader("Authorization", config.getAuthorizationHeader())
                .addHeader("Content-Type", "application/json")
                .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            return handleResponse(response, DeleteResponse.class);
        } catch (IOException e) {
            throw new DifyException("Failed to delete conversation", e);
        }
    }
    
    /**
     * 重命名对话
     * 
     * @param conversationId 对话ID
     * @param name 新名称
     * @param user 用户标识
     * @return 重命名结果
     * @throws DifyException 如果请求失败
     */
    public RenameResponse renameConversation(String conversationId, String name, String user) throws DifyException {
        String url = config.getFullUrl(CONVERSATIONS_ENDPOINT + "/" + conversationId + "/name");
        
        String json = String.format("{\"name\":\"%s\",\"user\":\"%s\"}", name, user);
        RequestBody body = RequestBody.create(json, JSON_MEDIA_TYPE);
        
        Request request = new Request.Builder()
                .url(url)
                .patch(body)
                .addHeader("Authorization", config.getAuthorizationHeader())
                .addHeader("Content-Type", "application/json")
                .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            return handleResponse(response, RenameResponse.class);
        } catch (IOException e) {
            throw new DifyException("Failed to rename conversation", e);
        }
    }
    
    /**
     * 获取应用参数
     * 
     * @param user 用户标识
     * @return 参数响应
     * @throws DifyException 如果请求失败
     */
    public ParametersResponse getParameters(String user) throws DifyException {
        String url = config.getFullUrl(PARAMETERS_ENDPOINT) + "?user=" + user;
        
        Request request = new Request.Builder()
                .url(url)
                .get()
                .addHeader("Authorization", config.getAuthorizationHeader())
                .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            return handleResponse(response, ParametersResponse.class);
        } catch (IOException e) {
            throw new DifyException("Failed to get parameters", e);
        }
    }
    
    // 内部响应类定义
    public static class ConversationResponse {
        // 根据实际API响应结构定义字段
    }
    
    public static class MessagesResponse {
        // 根据实际API响应结构定义字段
    }
    
    public static class ConversationsResponse {
        // 根据实际API响应结构定义字段
    }
    
    public static class DeleteResponse {
        // 根据实际API响应结构定义字段
    }
    
    public static class RenameResponse {
        // 根据实际API响应结构定义字段
    }
    
    public static class ParametersResponse {
        // 根据实际API响应结构定义字段
    }
}